package service

import (
	"basic-go/syntax/webook/internal/domain"
	"basic-go/syntax/webook/internal/repository"
	"context"
	"errors"
	"golang.org/x/crypto/bcrypt"
)

var (
	ErrUserDuplicate         = repository.ErrUserDuplicate
	ErrInvalidUserOrPassword = errors.New("账号/邮箱或密码不对")
	ErrUserNotFound          = repository.ErrUserNotFound
)

type UserService interface {
	Update(ctx context.Context, u domain.User) error
	SignUp(ctx context.Context, u domain.User) error
	Login(ctx context.Context, email, password string) (domain.User, error)
	//LoginV1(ctx context.Context, email, password string) (domain.User, error)
	Profile(ctx context.Context, id int64) (domain.User, error)
	FindOrCreateByPhone(ctx context.Context, phone string) (domain.User, error)
	FindByPhone(ctx context.Context, phone string) (domain.User, error)
	FindOrCreate(ctx context.Context, phone string) (domain.User, error)
	FindOrCreateByWechat(ctx context.Context, info domain.WechatInfo) (domain.User, error)
}

type userService struct {
	repo repository.UserRepository
}

func NewUserService(repo repository.UserRepository) UserService {
	return &userService{
		repo: repo,
	}
}

func (svc *userService) Update(ctx context.Context, u domain.User) error {

	return svc.repo.Update(ctx, u)
}

func (svc *userService) SignUp(ctx context.Context, u domain.User) error {
	// 密码加密
	hash, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost)
	if err != nil {
		return err
	}
	// hash是加密后的密码类型是[]byte, 将其转换成string类型，传入下一次，然后存入数据库
	u.Password = string(hash)
	return svc.repo.Create(ctx, u)
}

func (svc *userService) Login(ctx context.Context, email, password string) (domain.User, error) {

	//去调用repo查找用户
	uFindByRepo, err := svc.repo.FindByEmail(ctx, email)
	if err == repository.ErrUserNotFound {
		return domain.User{}, ErrInvalidUserOrPassword
	}
	if err != nil {
		return domain.User{}, err
	}

	// 找到用户，就对比密码是否一致
	err = bcrypt.CompareHashAndPassword([]byte(uFindByRepo.Password), []byte(password))
	if err != nil {
		return domain.User{}, ErrInvalidUserOrPassword
	}
	return uFindByRepo, nil
}

func (svc *userService) Profile(ctx context.Context, id int64) (domain.User, error) {
	u, err := svc.repo.SelectById(ctx, id)
	if err != nil {
		return domain.User{}, err
	}
	return u, nil
}

func (svc *userService) FindOrCreateByPhone(ctx context.Context, phone string) (domain.User, error) {
	u, err := svc.repo.FindOrCreateByPhone(ctx, phone)
	return u, err
}

func (svc *userService) FindByPhone(ctx context.Context, phone string) (domain.User, error) {
	u, err := svc.repo.FindByPhone(ctx, phone)
	return u, err
}

func (svc *userService) FindOrCreate(ctx context.Context, phone string) (domain.User, error) {
	u, err := svc.repo.FindByPhone(ctx, phone)
	if errors.Is(err, ErrUserNotFound) {
		// 数据库里没有这个用户就新建这个用户
		err := svc.repo.Create(ctx, domain.User{Phone: phone})
		if err != nil {
			return domain.User{}, err
		}
		return svc.repo.FindByPhone(ctx, phone)
	}
	return u, err
}

func (svc *userService) FindOrCreateByWechat(ctx context.Context, info domain.WechatInfo) (domain.User, error) {
	u, err := svc.repo.FindByWechat(ctx, info.OpenId)
	if errors.Is(err, ErrUserNotFound) {
		err := svc.repo.Create(ctx, domain.User{
			WechatInfo: info,
		})
		if err != nil {
			return domain.User{}, err
		}
		return svc.repo.FindByWechat(ctx, info.OpenId)
	}
	return u, err
}
